home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Utilities / MView / gxu / loadutil.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-30  |  32.3 KB  |  1,057 lines

  1. /*//////////////////////////////////////////////////////////////////////////////
  2. //
  3. // File: loadutil.cpp
  4. //
  5. // Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  6. //
  7. //
  8. //////////////////////////////////////////////////////////////////////////////*/
  9.  
  10. #include "pchgxu.h"
  11. #include "loadutil.h"
  12.  
  13. /*
  14.  * Template routine to handle dynamic allocation, based on Heap* Win32 APIs.
  15.  *
  16.  *  T **ppBase: base of array.
  17.  *  const T& obj: object to add to end of array.
  18.  *  UINT *pcNum: number of objects in array.
  19.  *  UINT *pcMax: max. number of objects in array.
  20.  *
  21.  * ppBase, pcNum and pcMax point to values that usually get modified
  22.  * by the call. The only case when they are not updated is if there
  23.  * is insufficient memory for the initial allocation (if *pBase is NULL)
  24.  * or a second allocation if *pcNum==*pcMax.
  25.  *
  26.  * Return value: TRUE if allocation was successful
  27.  *               FALSE if there was insufficient memory
  28.  *      FALSE means nothing was added to the array, but nothing
  29.  *        was lost either. No weird realloc semantics allowed!
  30.  */
  31. template<class T>
  32. BOOL
  33. AddToDynamicArray( T **ppBase, const T& obj, DWORD *pcNum, DWORD *pcMax )
  34. {
  35.     T *pBase = *ppBase;
  36.     if ( ! pBase )
  37.     {
  38.         HeapValidate( GetProcessHeap(), 0, NULL );
  39.         pBase = new T[2];
  40.         *pcNum = 0;
  41.         *pcMax = 2;
  42.     }
  43.     if ( *pcNum == *pcMax )
  44.     {
  45.         DWORD cNewMax = *pcMax*2;
  46.         T *newarr = new T[cNewMax];
  47.         if ( ! newarr )
  48.             return FALSE;
  49.         for (DWORD i = 0; i < *pcNum; i++)
  50.             newarr[i] = pBase[i];
  51.         *pcMax = cNewMax;
  52.         delete []pBase;
  53.         pBase = newarr;
  54.     }
  55.     pBase[ (*pcNum)++ ] = obj;
  56.     *ppBase = pBase;
  57.     return TRUE;
  58. }
  59. namespace GXU
  60. {
  61.  
  62.  
  63.  
  64.  
  65. HRESULT 
  66. SetVertexColor(SLoadedFace *pface, DWORD iPoint, D3DXCOLOR &color, SLoadVertex **prglvLoaded, DWORD *pcVertices, DWORD *pcVerticesMax)
  67. {
  68.     HRESULT hr = S_OK;
  69.     SLoadVertex *plvVertex;
  70.     SLoadVertex lvVertexNew;
  71.     DWORD iVertex;
  72.     DWORD iVertexNew;
  73.     DWORD wCur;
  74.     DWORD wHead;
  75.     SLoadVertex *plvCur;
  76.  
  77.     GXASSERT(pface != NULL && prglvLoaded != NULL && pcVertices != NULL && pcVerticesMax != NULL);
  78.  
  79.     iVertex = pface->m_wIndices[iPoint];
  80.     GXASSERT(iVertex < *pcVertices);
  81.  
  82.     plvVertex = &(*prglvLoaded)[iVertex];
  83.  
  84.     // if the vertex is not currently owned, take ownership
  85.     if (!plvVertex->m_bOwned)
  86.     {
  87.         plvVertex->m_bOwned = true;
  88.         plvVertex->m_color = color;
  89.     }
  90.     // else if the vertex is owned but the color is not the same 
  91.     //   NOTE: if the same, then just ignore the fact that the color was being set
  92.     else if (plvVertex->m_color != color)
  93.     {
  94.         lvVertexNew = *plvVertex;
  95.         GXASSERT(lvVertexNew.m_bOwned);
  96.  
  97.         // UNDONE - this is currently rechecking the first vertex, might be possible
  98.         //   to skip depending on sematics of the mesh file
  99.         wHead = iVertex;
  100.         wCur = wHead;
  101.         do
  102.         {
  103.             plvCur = &( (*prglvLoaded)[wCur] );
  104.  
  105.             if (plvCur->m_color == color)
  106.             {
  107.                 // found an equivalent wedge, just point at it
  108.                 pface->m_wIndices[iPoint] = wCur;
  109.                 goto e_Exit;
  110.             }
  111.  
  112.             // go to next wedge in the vertex
  113.             wCur = (*prglvLoaded)[wCur].m_wPointList;
  114.         } while (wCur != wHead);
  115.  
  116.         // set both the color and the representative point to create a new vertex that is 
  117.         //   logically the same in the mesh, but has a different color attribute
  118.         lvVertexNew.m_color = color;
  119.         lvVertexNew.m_wPointRep = (*prglvLoaded)[iVertex].m_wPointRep;
  120.  
  121.         iVertexNew = (DWORD)*pcVertices;
  122.  
  123.         if ( ! AddToDynamicArray( prglvLoaded, lvVertexNew, pcVertices, pcVerticesMax ) )
  124.         {
  125.             hr = E_OUTOFMEMORY;
  126.             goto e_Exit;
  127.         }
  128.  
  129.         (*prglvLoaded)[iVertexNew].m_wPointList = (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList;
  130.         (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList = iVertexNew;
  131.  
  132.         // now update the face to refer to the new point with the correct attributes
  133.         pface->m_wIndices[iPoint] = iVertexNew;
  134.     }
  135.  
  136. e_Exit:
  137.     return hr;
  138. }
  139.  
  140. HRESULT 
  141. SetVertexAttributes(SLoadedFace *pface, DWORD iPoint, D3DXVECTOR3 *pvNormal, D3DXVECTOR2 *puvTex1, SLoadVertex **prglvLoaded, DWORD *pcVertices, DWORD *pcVerticesMax)
  142. {
  143.     HRESULT hr = S_OK;
  144.     SLoadVertex *plvVertex;
  145.     SLoadVertex lvVertexNew;
  146.     DWORD iVertex;
  147.     DWORD iVertexNew;
  148.     DWORD wCur;
  149.     DWORD wHead;
  150.     SLoadVertex *plvCur;
  151.  
  152.     GXASSERT(pface != NULL && prglvLoaded != NULL && pcVertices != NULL && pcVerticesMax != NULL);
  153.  
  154.     iVertex = pface->m_wIndices[iPoint];
  155.     GXASSERT(iVertex < *pcVertices);
  156.  
  157.     plvVertex = &(*prglvLoaded)[iVertex];
  158.  
  159.     // UNDONE craigp - It might be useful to search all instances of a logical vertex
  160.     //   in order to find another one to share with
  161.  
  162.     // if the vertex is not currently owned, take ownership
  163.     if (!plvVertex->m_bOwned)
  164.     {
  165.         plvVertex->m_bOwned = true;
  166.  
  167.         if (pvNormal != NULL)
  168.             plvVertex->m_vNormal = *pvNormal;
  169.  
  170.         if (puvTex1 != NULL)
  171.             plvVertex->m_uvTex1 = *puvTex1;
  172.     }
  173.     else if (((pvNormal != NULL) && (plvVertex->m_vNormal != *pvNormal))
  174.             || ((puvTex1 != NULL) && (plvVertex->m_uvTex1 != *puvTex1)))
  175.     {
  176.         lvVertexNew = *plvVertex;
  177.         GXASSERT(lvVertexNew.m_bOwned);
  178.  
  179.         // set both the attributes and the representative point to create a new vertex that is 
  180.         //   logically the same in the mesh, but has a different vertex attributes
  181.  
  182.         if (pvNormal != NULL)
  183.             lvVertexNew.m_vNormal = *pvNormal;
  184.  
  185.         if (puvTex1 != NULL)
  186.             plvVertex->m_uvTex1 = *puvTex1;
  187.  
  188.         // UNDONE - this is currently rechecking the first vertex, might be possible
  189.         //   to skip depending on sematics of the mesh file
  190.         wHead = iVertex;
  191.         wCur = wHead;
  192.         do
  193.         {
  194.             plvCur = &( (*prglvLoaded)[wCur] );
  195.  
  196.             if (plvCur->m_bOwned && BEqualWedges(*plvCur, lvVertexNew))
  197.             {
  198.                 // found an equivalent wedge, just point at it
  199.                 pface->m_wIndices[iPoint] = wCur;
  200.                 goto e_Exit;
  201.             }
  202.  
  203.             // go to next wedge in the vertex
  204.             wCur = (*prglvLoaded)[wCur].m_wPointList;
  205.         } while (wCur != wHead);
  206.  
  207.         lvVertexNew.m_wPointRep = (*prglvLoaded)[iVertex].m_wPointRep;
  208.  
  209.         iVertexNew = (DWORD)*pcVertices;
  210.  
  211.         if ( ! AddToDynamicArray( prglvLoaded, lvVertexNew, pcVertices, pcVerticesMax ) )
  212.         {
  213.             hr = E_OUTOFMEMORY;
  214.             goto e_Exit;
  215.         }
  216.  
  217.         // link the vertex in to the vertex list
  218.         (*prglvLoaded)[iVertexNew].m_wPointList = (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList;
  219.         (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList = iVertexNew;
  220.  
  221.         // now update the face to refer to the new point with the correct attributes
  222.         pface->m_wIndices[iPoint] = iVertexNew;
  223.     }
  224.  
  225. e_Exit:
  226.     return hr;
  227. }
  228.  
  229. HRESULT 
  230. SetSmoothingGroup(SLoadedFace *pface, DWORD iPoint, WORD iSmoothingGroup, D3DXVECTOR3 &vNormal, SLoadVertex **prglvLoaded, DWORD *pcVertices, DWORD *pcVerticesMax)
  231. {
  232.     HRESULT hr = S_OK;
  233.     SLoadVertex *plvVertex;
  234.     SLoadVertex lvVertexNew;
  235.     DWORD iVertex;
  236.     DWORD iVertexNew;
  237.     DWORD wCur;
  238.     DWORD wHead;
  239.     DWORD wWedgeFound;
  240.     SLoadVertex *plvCur;
  241.  
  242.     GXASSERT(pface != NULL && prglvLoaded != NULL && pcVertices != NULL && pcVerticesMax != NULL);
  243.  
  244.     iVertex = pface->m_wIndices[iPoint];
  245.     GXASSERT(iVertex < *pcVertices);
  246.  
  247.     plvVertex = &(*prglvLoaded)[iVertex];
  248.  
  249.     // if the vertex is not currently owned, take ownership
  250.     if (plvVertex->m_cSmoothingGroupFaces == 0)
  251.     {
  252.         GXASSERT(plvVertex->m_iSmoothingGroup == 0);
  253.  
  254.         plvVertex->m_cSmoothingGroupFaces = 1;
  255.         plvVertex->m_iSmoothingGroup = iSmoothingGroup;
  256.  
  257.         plvVertex->m_vNormal = vNormal;
  258.     }
  259.     else
  260.     {       
  261.  
  262.         if (iSmoothingGroup > 0)
  263.         {
  264.             wHead = iVertex;
  265.             wCur = wHead;
  266.             wWedgeFound = UNUSED32;
  267.             do
  268.             {
  269.                 plvCur = &( (*prglvLoaded)[wCur] );
  270.  
  271.                 if (plvVertex->m_iSmoothingGroup == iSmoothingGroup)
  272.                 {
  273.                     // found a wedge of this smoothing group
  274.                     wWedgeFound = wCur;
  275.                     break;
  276.                 }
  277.  
  278.                 // go to next wedge in the vertex
  279.                 wCur = (*prglvLoaded)[wCur].m_wPointList;
  280.             } while (wCur != wHead);
  281.         }
  282.         else  // in the 0 case, need to approximate flat shading so always
  283.             //  insert a new wedge
  284.         {           
  285.             wHead = iVertex;
  286.             wCur = wHead;
  287.             wWedgeFound = UNUSED32;
  288.             do
  289.             {
  290.                 plvCur = &( (*prglvLoaded)[wCur] );
  291.  
  292.                 if ((plvVertex->m_iSmoothingGroup == iSmoothingGroup) &&
  293.                     (plvVertex->m_vNormal == vNormal))
  294.                 {
  295.                     // found a wedge of this smoothing group
  296.                     wWedgeFound = wCur;
  297.                     break;
  298.                 }
  299.  
  300.                 // go to next wedge in the vertex
  301.                 wCur = (*prglvLoaded)[wCur].m_wPointList;
  302.             } while (wCur != wHead);
  303.         }
  304.  
  305.         // if a wedge was found, add the current normal in to the wedge
  306.         if (wWedgeFound != UNUSED32)
  307.         {
  308.             (*prglvLoaded)[wWedgeFound].m_cSmoothingGroupFaces += 1;
  309.             (*prglvLoaded)[wWedgeFound].m_vNormal += vNormal;
  310.  
  311.             // now update the face to refer to the new point with the correct attributes
  312.             pface->m_wIndices[iPoint] = wWedgeFound;
  313.         }
  314.         else  // if no matching wedge found.  add a new wedge
  315.         {
  316.             lvVertexNew = *plvVertex;
  317.  
  318.             lvVertexNew.m_wPointRep = (*prglvLoaded)[iVertex].m_wPointRep;
  319.  
  320.             lvVertexNew.m_iSmoothingGroup = iSmoothingGroup;
  321.             lvVertexNew.m_cSmoothingGroupFaces = 1;
  322.             lvVertexNew.m_vNormal = vNormal;
  323.  
  324.             iVertexNew = (DWORD)*pcVertices;
  325.  
  326.             if ( ! AddToDynamicArray( prglvLoaded, lvVertexNew, pcVertices, pcVerticesMax ) )
  327.             {
  328.                 hr = E_OUTOFMEMORY;
  329.                 goto e_Exit;
  330.             }
  331.  
  332.             // link the vertex in to the vertex list
  333.             (*prglvLoaded)[iVertexNew].m_wPointList = (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList;
  334.             (*prglvLoaded)[lvVertexNew.m_wPointRep].m_wPointList = iVertexNew;
  335.  
  336.             // now update the face to refer to the new point with the correct attributes
  337.             pface->m_wIndices[iPoint] = iVertexNew;
  338.         }
  339.  
  340.     }
  341.  
  342. e_Exit:
  343.     return hr;
  344. }
  345.  
  346. DWORD 
  347. FindPoint(PDWORD pwIndices, DWORD iPointSearch, SLoadVertex *rglvVerts)
  348. {
  349.     DWORD iPoint;
  350.  
  351.     // get the representative for the point, so that we can compare
  352.     //   them, this function compares the logical points in the mesh
  353.     DWORD wPointSearchRep = rglvVerts[iPointSearch].m_wPointRep;
  354.  
  355.     for (iPoint = 0; iPoint < 3; iPoint++)
  356.     {
  357.         if (rglvVerts[pwIndices[iPoint]].m_wPointRep == wPointSearchRep)
  358.         {
  359.             break;
  360.         }
  361.     }
  362.  
  363.     return iPoint;
  364. }
  365.  
  366. HRESULT  
  367. InitVertices(SLoadVertex *&rglvVertices, DWORD cVertices)
  368. {
  369.     HRESULT hr = S_OK;
  370.     DWORD iVertex;
  371.  
  372.     rglvVertices = new SLoadVertex[cVertices];
  373.     if (rglvVertices == NULL)
  374.     {
  375.         hr = E_OUTOFMEMORY;
  376.         goto e_Exit;
  377.     }
  378.  
  379.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  380.     {
  381.         rglvVertices[iVertex].m_vPos = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  382.         rglvVertices[iVertex].m_vNormal = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  383. //        rglvVertices[iVertex].m_color = D3DXCOLOR(0.9f, 0.6f, 0.4f, 0.0f);
  384.         rglvVertices[iVertex].m_color = D3DXCOLOR(1.0f, 1.0f, 1.0f, 0.0f);
  385.         rglvVertices[iVertex].m_uvTex1 = D3DXVECTOR2(0.0f, 0.0f);
  386.         rglvVertices[iVertex].m_wPointRep = iVertex;
  387.         rglvVertices[iVertex].m_wPointList = iVertex;
  388.         rglvVertices[iVertex].m_bOwned = false;
  389.         rglvVertices[iVertex].m_iFVFDataOffset = iVertex;
  390.  
  391.         rglvVertices[iVertex].m_iSmoothingGroup = 0;
  392.         rglvVertices[iVertex].m_cSmoothingGroupFaces = 0;
  393.     }
  394.  
  395. e_Exit:
  396.     return hr;
  397. }
  398.  
  399. HRESULT 
  400. InitCorners(SCorner *&rgCorners, DWORD cCorners)
  401. {
  402.     HRESULT hr = S_OK;
  403.     DWORD iCorner;
  404.  
  405.     rgCorners = new SCorner[cCorners];
  406.     if (rgCorners == NULL)
  407.     {
  408.         hr = E_OUTOFMEMORY;
  409.         goto e_Exit;
  410.     }
  411.  
  412.     for (iCorner = 0; iCorner < cCorners; iCorner++)
  413.     {
  414.         rgCorners[iCorner].m_wPoint = UNUSED32;
  415.         rgCorners[iCorner].m_wFace = UNUSED32;
  416.  
  417.         rgCorners[iCorner].m_vNormal = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
  418.         rgCorners[iCorner].m_uvTex1 = D3DXVECTOR2(0.0f, 0.0f);
  419.  
  420.         rgCorners[iCorner].m_bNormalSpecified = false;
  421.         rgCorners[iCorner].m_bUvSpecified = false;
  422.     }
  423.  
  424. e_Exit:
  425.     return hr;
  426. }
  427.  
  428. HRESULT 
  429. InitFaces(SLoadedFace *&rglfFaces, DWORD cFaces)
  430. {
  431.     HRESULT hr = S_OK;
  432.     DWORD iFace;
  433.  
  434.     rglfFaces = new SLoadedFace[cFaces];
  435.     if (rglfFaces == NULL)
  436.     {
  437.         hr = E_OUTOFMEMORY;
  438.         goto e_Exit;
  439.     }
  440.  
  441.     for (iFace = 0; iFace < cFaces; iFace++)
  442.     {
  443.         rglfFaces[iFace].InitEmpty();
  444.     }
  445.  
  446. e_Exit:
  447.     return hr;
  448. }
  449.  
  450. bool
  451. BEqualWedges(SLoadVertex &lv1, SLoadVertex &lv2)
  452. {
  453.  
  454.     return (lv1.m_color == lv2.m_color) 
  455.         && (lv1.m_uvTex1 == lv2.m_uvTex1)
  456.         && (lv1.m_vNormal == lv2.m_vNormal);
  457. }
  458.  
  459.  
  460. D3DCOLOR
  461. ConvertColor(D3DXCOLOR &color)
  462. {
  463.     DWORD _r, _g, _b, _a;
  464.     if (color.r < 0.0f) _r = 0;
  465.     else if (color.r > 1.0f) _r = 0xff;
  466.     else _r = (DWORD) (color.r*255.0f+0.5f);
  467.     if (color.g < 0.0f) _g = 0;
  468.     else if (color.g > 1.0f) _g = 0xff;
  469.     else _g = (DWORD) (color.g*255.0f+0.5f);
  470.     if (color.b < 0.0f) _b = 0;
  471.     else if (color.b > 1.0f) _b = 0xff;
  472.     else _b = (DWORD) (color.b*255.0f+0.5f);
  473.     if (color.a < 0.0f) _a = 0;
  474.     else if (color.a > 1.0f) _a = 0xff;
  475.     else _a = (DWORD) (color.a*255.0f+0.5f);
  476.     return RGBA_MAKE( _r, _g, _b, _a);
  477. }
  478.  
  479. HRESULT 
  480. SetMesh(SLoadedFace *&rglfFaces, DWORD cFaces, 
  481.                 SLoadVertex *&rglvLoaded, DWORD cVertices, 
  482.                 SCorner *rgCorners, DWORD cCorners,
  483.                 SFVFData *pFVFData, BOOL bUsePointRepData, DWORD *rgdwAdjacencyFile,
  484.                 DWORD dwOptions, DWORD dwFVF, LPDIRECT3DDEVICE9 pD3DDevice, 
  485.                 LPD3DXMESH *ppMesh, LPD3DXBUFFER *ppbufAdjacency)
  486. {
  487.     HRESULT hr = S_OK;
  488.     PBYTE pvPoints = NULL;
  489.     D3DXVECTOR3 vNormal;
  490.  
  491.     DWORD iVertex;
  492.     D3DXVECTOR3 *pvNormal;
  493.     D3DXVECTOR2 *puvTex1;
  494.     DWORD iPoint;
  495.     DWORD iFace;
  496.     DWORD iCorner;
  497.     PBYTE pvCurPoint;
  498.     DWORD iWeight;
  499.     DWORD iTexCoord;
  500.     DWORD iInitialTexCoord;
  501.     PBYTE pbCur;
  502.     DWORD cFacesActual;
  503.     DWORD iFaceActual;
  504.  
  505.     ID3DXMesh *ptmMesh = NULL;
  506.     DWORD *rgdwFaces = NULL;
  507.     UINT16 *rgwFaces = NULL;
  508.     DWORD *rgiAttribIds = NULL;
  509.     DWORD *pdwFaceCur;
  510.     UINT16 *pwFaceCur;
  511.     PVOID pvFaces = NULL;
  512.  
  513.     DWORD cVerticesMax = cVertices;
  514.     BOOL bSmoothingGroups;
  515.  
  516.     DWORD *rgdwPointRepsTemp = NULL;
  517.     LPD3DXBUFFER pbufAdjacency = NULL;
  518.     DWORD *pdwAdjacency;
  519.     DWORD rgdwTexCoordSizesOtherData[8];
  520.     PBYTE pbTexCur;
  521.     DWORD *rgdwFaceRemap = NULL;
  522.  
  523.     GXASSERT(ppMesh != NULL);
  524.     GXASSERT(rglfFaces != NULL);
  525.     GXASSERT(rglvLoaded != NULL);
  526.     // Corners are allowed to be NULL
  527.     DXCrackFVF  cfvf(dwFVF);                                
  528.     DXCrackFVF  cfvfOtherData(pFVFData != NULL ? pFVFData->dwFVF : D3DFVF_XYZ);                                
  529.  
  530.     cfvfOtherData.GetTexCoordSizes(rgdwTexCoordSizesOtherData);
  531.  
  532.     // handle smoothing groups
  533.     bSmoothingGroups = false;
  534.     for (iFace = 0; iFace < cFaces; iFace++)
  535.     {
  536.         if (rglfFaces[iFace].m_bSmoothingGroupSpecified)
  537.         {
  538.             bSmoothingGroups = true;
  539.         }
  540.     }
  541.  
  542.     // if there are smoothing groups, and the normals are there is a 
  543.     //   reason to compute smoothing groups, then compute them.
  544.     if (bSmoothingGroups && cfvf.BNormal())
  545.     {
  546.         SLoadedFace *plfFace;
  547.         SLoadVertex *plvPos0;
  548.         SLoadVertex *plvPos1;
  549.         SLoadVertex *plvPos2;
  550.         D3DXVECTOR3 vEdge1;
  551.         D3DXVECTOR3 vEdge2;
  552.         SLoadVertex *plvVert;
  553.         DWORD iVert;
  554.  
  555.         for (iFace = 0 ; iFace < cFaces; iFace++)
  556.         {
  557.             plfFace = &rglfFaces[iFace];
  558.             if (plfFace->m_bSmoothingGroupSpecified)
  559.             {
  560.                 plvPos0 = &rglvLoaded[plfFace->m_wIndices[0]];
  561.                 plvPos1 = &rglvLoaded[plfFace->m_wIndices[1]];
  562.                 plvPos2 = &rglvLoaded[plfFace->m_wIndices[2]];
  563.  
  564.                 vEdge1 = plvPos0->m_vPos - plvPos1->m_vPos;
  565.                 vEdge2 = plvPos0->m_vPos - plvPos2->m_vPos;
  566.  
  567.                 // calculate the normal of the face from the two edge vectors
  568.                 D3DXVec3Cross(&vNormal, &vEdge1, &vEdge2);
  569.                 vNormal /= D3DXVec3Length(&vNormal);
  570.                 //vNormal *= -1;
  571.  
  572.                 for (iPoint = 0; iPoint < 3; iPoint++)
  573.                 {
  574.                     hr = SetSmoothingGroup(&rglfFaces[iFace], iPoint, rglfFaces[iFace].m_iSmoothingGroup, vNormal, &rglvLoaded, &cVertices, &cVerticesMax);
  575.                     if (FAILED(hr))
  576.                         goto e_Exit;
  577.                 }
  578.             }
  579.         }
  580.  
  581.         DWORD iTest;
  582.         iTest = 0;
  583.         // average and renormalize vertices shared among faces of the same smoothing group
  584.         for (iVert = 0; iVert < cVertices; iVert++)
  585.         {
  586.             plvVert = &rglvLoaded[iVert];
  587.  
  588.             if (plvVert->m_cSmoothingGroupFaces > 1)
  589.             {
  590.                 /*plvVert->m_vNormal /= plvVert->m_cSmoothingGroupFaces*/;
  591.                 plvVert->m_vNormal /= D3DXVec3Length(&plvVert->m_vNormal);
  592.             }
  593.  
  594.             if (plvVert->m_iSmoothingGroup == 0)
  595.             {
  596.                 iTest += 1;
  597.             }
  598.         }
  599.  
  600.     }
  601.  
  602.     if (cfvf.BDiffuse())
  603.     {
  604.         // propagate face color attributes into vertex attributes
  605.         for (iFace = 0; iFace < cFaces; iFace++)
  606.         {
  607.             if (rglfFaces[iFace].m_bColorSpecified)
  608.             {
  609.                 for (iPoint = 0; iPoint < 3; iPoint++)
  610.                 {
  611.                     hr = SetVertexColor(&rglfFaces[iFace], iPoint, rglfFaces[iFace].m_colorFace, &rglvLoaded, &cVertices, &cVerticesMax);
  612.                     if (FAILED(hr))
  613.                         goto e_Exit;
  614.                 }
  615.             }
  616.  
  617.         }
  618.     }
  619.  
  620.     // after dealing face attributes, reset owned flags to false, and reprocess
  621.     // the 
  622.     for (iVertex = 0; iVertex < cVertices; iVertex++)
  623.     {
  624.         rglvLoaded[iVertex].m_bOwned = false;
  625.     }
  626.  
  627.     // propogate corner attributes into vertex attributes
  628.     for (iCorner = 0; iCorner < cCorners; iCorner++)
  629.     {
  630.         if (rgCorners[iCorner].m_bNormalSpecified || rgCorners[iCorner].m_bUvSpecified)
  631.         {
  632.             iFace = rgCorners[iCorner].m_wFace;
  633.             if ((iFace >= cFaces) || (rglfFaces[iFace].m_wIndices[0] == UNUSED32))
  634.                 continue;
  635.  
  636.             iPoint = FindPoint(rglfFaces[iFace].m_wIndices, rgCorners[iCorner].m_wPoint, rglvLoaded);
  637.  
  638.             GXASSERT(iPoint < 3);
  639.  
  640.             pvNormal = NULL;
  641.             if (rgCorners[iCorner].m_bNormalSpecified && cfvf.BNormal())
  642.             {
  643.                 pvNormal = &rgCorners[iCorner].m_vNormal;
  644.             }
  645.             
  646.             puvTex1 = NULL;
  647.             if (rgCorners[iCorner].m_bUvSpecified && cfvf.BTex1())
  648.             {
  649.                 puvTex1 = &rgCorners[iCorner].m_uvTex1;
  650.             }
  651.  
  652.             hr = SetVertexAttributes(&rglfFaces[iFace], iPoint, pvNormal, puvTex1, &rglvLoaded, &cVertices, &cVerticesMax);
  653.             if (FAILED(hr))
  654.                 goto e_Exit;
  655.         }
  656.     }
  657.  
  658.  
  659.     if ((cFaces >= UNUSED16) || (cVertices >= UNUSED16))
  660.     {
  661.         dwOptions |= D3DXMESH_32BIT;
  662.     }
  663.  
  664.     // need to remove degenerate triangles
  665.     cFacesActual = 0;
  666.     for (iFace = 0; iFace < cFaces; iFace++)
  667.     {
  668.         if ((rglfFaces[iFace].m_wIndices[0] == rglfFaces[iFace].m_wIndices[1])
  669.             || (rglfFaces[iFace].m_wIndices[0] == rglfFaces[iFace].m_wIndices[2])
  670.             || (rglfFaces[iFace].m_wIndices[1] == rglfFaces[iFace].m_wIndices[2]))
  671.         {
  672.             rglfFaces[iFace].m_wIndices[0] = UNUSED32;
  673.             rglfFaces[iFace].m_wIndices[1] = UNUSED32;
  674.             rglfFaces[iFace].m_wIndices[2] = UNUSED32;
  675.         }
  676.         else
  677.         {
  678.             cFacesActual += 1;
  679.         }
  680.     }
  681.  
  682.     if ((cFacesActual == 0) || (cVertices == 0))
  683.     {
  684.         hr = D3DXERR_LOADEDMESHASNODATA;
  685.         goto e_Exit;
  686.     }
  687.  
  688.     // create the mesh now that we know the correct size
  689.     hr = D3DXCreateMeshFVF(cFacesActual, cVertices, dwOptions, dwFVF, pD3DDevice, &ptmMesh);
  690.     if (FAILED(hr))
  691.         goto e_Exit;
  692.  
  693.     // get the vertex buffer, fill the vertices in place
  694.     hr = ptmMesh->LockVertexBuffer(0, (PVOID*)&pvPoints);
  695.     if (FAILED(hr))
  696.         goto e_Exit;
  697.  
  698.     // transform the points into the proper FVF format
  699.     for (iPoint=0, pvCurPoint = pvPoints; iPoint < cVertices; iPoint++, pvCurPoint+=cfvf.m_cBytesPerVertex)
  700.     {
  701.         cfvf.SetPosition(pvCurPoint, &rglvLoaded[iPoint].m_vPos);
  702.  
  703.         cfvf.SetNormal(pvCurPoint, &rglvLoaded[iPoint].m_vNormal);
  704.         cfvf.SetDiffuse(pvCurPoint, ConvertColor(rglvLoaded[iPoint].m_color));
  705.         cfvf.SetTex1(pvCurPoint, &rglvLoaded[iPoint].m_uvTex1);
  706.  
  707.         if (pFVFData != NULL)
  708.         {
  709.             pbCur = (PBYTE)&pFVFData->rgiFVFData[pFVFData->cBytesPerVertex/sizeof(DWORD) * rglvLoaded[iPoint].m_iFVFDataOffset];
  710.  
  711.             if (cfvfOtherData.CWeights() > 0)
  712.             {
  713.                 for (iWeight = 0; iWeight < cfvfOtherData.CWeights(); iWeight++)
  714.                 {
  715.                     cfvf.SetWeight(pvCurPoint, iWeight, *(float*)pbCur);
  716.                     pbCur += sizeof(float);
  717.                 }
  718.             }
  719.  
  720.             if (cfvfOtherData.BNormal())
  721.             {
  722.                 cfvf.SetNormal(pvCurPoint, (D3DXVECTOR3*)pbCur);
  723.                 pbCur += sizeof(D3DXVECTOR3);
  724.             }
  725.  
  726.             if (cfvfOtherData.BDiffuse())
  727.             {
  728.                 cfvf.SetDiffuse(pvCurPoint, *(D3DCOLOR*)pbCur);
  729.                 pbCur += sizeof(D3DCOLOR);
  730.             }
  731.  
  732.             if (cfvfOtherData.BSpecular())
  733.             {
  734.                 cfvf.SetSpecular(pvCurPoint, *(D3DCOLOR*)pbCur);
  735.                 pbCur += sizeof(D3DCOLOR);
  736.             }
  737.  
  738.             if (cfvfOtherData.CTexCoords() > 0)
  739.             {
  740.                 // UNDONE UNDONE - fix when 3d tex coords are handled
  741.                 //iInitialTexCoord = cfvf.BTex1() ? 1 : 0;
  742.                 iInitialTexCoord = pFVFData->iTexCoordOffset;
  743.  
  744.                 pbTexCur = (PBYTE)cfvf.PuvGetTex1(pvCurPoint);
  745.  
  746.                 // if offset into the FVF, then move the texture pointer to the correct
  747.                 //    starting position. i.e. 2d coord from template and other coords from fvf data
  748.                 for (iTexCoord = 0; iTexCoord < iInitialTexCoord; iTexCoord++)
  749.                 {
  750.                     pbTexCur += cfvf.CbTexCoordSize(iTexCoord);
  751.                 }
  752.  
  753.                 for (iTexCoord = 0; iTexCoord < cfvfOtherData.CTexCoords(); iTexCoord++)
  754.                 {
  755.                     memcpy(pbTexCur, pbCur, sizeof(BYTE) * rgdwTexCoordSizesOtherData[iTexCoord]);
  756.                     pbTexCur += rgdwTexCoordSizesOtherData[iTexCoord];
  757.                     pbCur += rgdwTexCoordSizesOtherData[iTexCoord];
  758.                 }
  759.             }
  760.         }
  761.     }
  762.  
  763.     hr = ptmMesh->LockIndexBuffer(0, (LPVOID*)&pvFaces);
  764.     if (FAILED(hr))
  765.         goto e_Exit;
  766.  
  767.     hr = ptmMesh->LockAttributeBuffer(0, &rgiAttribIds);
  768.     if (FAILED(hr))
  769.         goto e_Exit;
  770.  
  771.     // copy the material data to arrays understood by ID3DXMesh::SetMesh
  772.     for (iFace = iFaceActual = 0; iFace < cFaces; iFace++)
  773.     {
  774.         if (rglfFaces[iFace].m_wIndices[0] == UNUSED32)
  775.             continue;
  776.  
  777.         if (rglfFaces[iFace].m_bAttributeSpecified)
  778.         {
  779.             rgiAttribIds[iFaceActual] = rglfFaces[iFace].m_attr;
  780.         }
  781.         else
  782.         {
  783.             //rgiAttribIds[iFace] = UNUSED32;
  784.             rgiAttribIds[iFaceActual] = 0;
  785.         }
  786.  
  787.         iFaceActual += 1;
  788.     }
  789.  
  790.     if ( dwOptions & D3DXMESH_32BIT)
  791.     {
  792.         rgdwFaces = (DWORD*)pvFaces;
  793.  
  794.         for (iFace = 0, pdwFaceCur = rgdwFaces; iFace < cFaces; iFace++)
  795.         {
  796.             if (rglfFaces[iFace].m_wIndices[0] == UNUSED32)
  797.                 continue;
  798.  
  799.             pdwFaceCur[0] = rglfFaces[iFace].m_wIndices[0];
  800.             pdwFaceCur[1] = rglfFaces[iFace].m_wIndices[1];
  801.             pdwFaceCur[2] = rglfFaces[iFace].m_wIndices[2];
  802.             pdwFaceCur += 3;
  803.         }
  804.     }
  805.     else // 16 bit indices
  806.     {
  807.         rgwFaces = (UINT16*)pvFaces;
  808.  
  809.         for (iFace = 0, pwFaceCur = rgwFaces; iFace < cFaces; iFace++)
  810.         {
  811.             if (rglfFaces[iFace].m_wIndices[0] == UNUSED32)
  812.                 continue;
  813.  
  814.             pwFaceCur[0] = (UINT16)rglfFaces[iFace].m_wIndices[0];
  815.             pwFaceCur[1] = (UINT16)rglfFaces[iFace].m_wIndices[1];
  816.             pwFaceCur[2] = (UINT16)rglfFaces[iFace].m_wIndices[2];
  817.  
  818.             pwFaceCur += 3;
  819.         }
  820.     }
  821.  
  822.     ptmMesh->UnlockAttributeBuffer();
  823.     rgiAttribIds = NULL;
  824.     ptmMesh->UnlockIndexBuffer();
  825.     pvFaces = NULL;
  826.     ptmMesh->UnlockVertexBuffer();
  827.     pvPoints = NULL;
  828.  
  829.     // if adjacency information is desired, generate it from point rep information
  830.     if (ppbufAdjacency != NULL)
  831.     {
  832.         hr = D3DXCreateBuffer(cFacesActual * 3 * sizeof(DWORD), &pbufAdjacency);
  833.         if (FAILED(hr))
  834.             goto e_Exit;
  835.         
  836.         pdwAdjacency = (DWORD*)pbufAdjacency->GetBufferPointer();
  837.         GXASSERT(cFacesActual * 3 * sizeof(DWORD) == pbufAdjacency->GetBufferSize());
  838.  
  839.         rgdwPointRepsTemp = new DWORD[cVertices];
  840.         if (rgdwPointRepsTemp == NULL)
  841.         {
  842.             hr = E_OUTOFMEMORY;
  843.             goto e_Exit;
  844.         }
  845.  
  846.         // load the point reps into the temp array
  847.         for (iPoint = 0; iPoint < cVertices; iPoint++)
  848.         {
  849.             rgdwPointRepsTemp[iPoint] = rglvLoaded[iPoint].m_wPointRep;
  850.         }
  851.  
  852.         // if adjacency was provided copy it (remap if faces removed)
  853.         if (rgdwAdjacencyFile != NULL)
  854.         {
  855.             if (cFacesActual == cFaces)
  856.             {
  857.                 memcpy(pdwAdjacency, rgdwAdjacencyFile, sizeof(DWORD) * 3 * cFacesActual);
  858.             }
  859.             else
  860.             {
  861.                 rgdwFaceRemap = new DWORD[cFaces];
  862.                 if (rgdwFaceRemap == NULL)
  863.                 {
  864.                     hr = E_OUTOFMEMORY;
  865.                     goto e_Exit;
  866.                 }
  867.  
  868.                 // generate a remapping to ignore removed faces
  869.                 for (iFace = iFaceActual = 0; iFace < cFaces; iFace++)
  870.                 {
  871.                     if (rglfFaces[iFace].m_wIndices[0] == UNUSED32)
  872.                     {
  873.                         rgdwFaceRemap[iFace] = UNUSED32;
  874.                     }
  875.                     else
  876.                     {
  877.                         rgdwFaceRemap[iFace] = iFaceActual;
  878.                         iFaceActual += 1;
  879.                     }
  880.                 }
  881.  
  882.                 // now copy and remap the face adjacency
  883.                 for (iFace = iFaceActual = 0; iFace < cFaces; iFace++)
  884.                 {
  885.                     if (rgdwFaceRemap[iFace] == UNUSED32)
  886.                         continue;
  887.  
  888.                     for (iPoint = 0; iPoint < 3; iPoint++)
  889.                     {
  890.                         if (rgdwAdjacencyFile[iFace * 3 + iPoint] != UNUSED32)
  891.                             pdwAdjacency[iFaceActual * 3 + iPoint] = rgdwFaceRemap[rgdwAdjacencyFile[iFace * 3 + iPoint]];
  892.                         else
  893.                             pdwAdjacency[iFaceActual * 3 + iPoint] = UNUSED32;
  894.                     }
  895.  
  896.                     iFaceActual += 1;
  897.                 }
  898.  
  899.             }
  900.         }
  901.         // if point rep data provided, use it to generate adjacency
  902.         else if (bUsePointRepData)
  903.         {
  904.             hr = ptmMesh->ConvertPointRepsToAdjacency(rgdwPointRepsTemp, pdwAdjacency);
  905.             if (FAILED(hr))
  906.                 goto e_Exit;
  907.         }
  908.         else  // generate adjacency based on position of vertices
  909.         {
  910.             hr = ptmMesh->GenerateAdjacency(0.0f, pdwAdjacency);
  911.             if (FAILED(hr))
  912.                 goto e_Exit;
  913.         }
  914.  
  915.         *ppbufAdjacency = pbufAdjacency;
  916.         pbufAdjacency = NULL;
  917.     }
  918.  
  919.     *ppMesh = ptmMesh;
  920. e_Exit:
  921.     if (rgiAttribIds != NULL)
  922.     {
  923.         ptmMesh->UnlockAttributeBuffer();
  924.     }
  925.     if (pvFaces != NULL)
  926.     {
  927.         ptmMesh->UnlockIndexBuffer();
  928.     }
  929.  
  930.     delete []rgdwPointRepsTemp;
  931.     delete []rgdwFaceRemap;
  932.  
  933.     GXRELEASE(pbufAdjacency);
  934.  
  935.     if (pvPoints != NULL)
  936.     {
  937.         ptmMesh->UnlockVertexBuffer();
  938.     }
  939.  
  940.     if (FAILED(hr))
  941.         GXRELEASE(ptmMesh);
  942.  
  943.     return hr;
  944. }
  945.  
  946.  
  947. HRESULT
  948. CreateMaterialBuffer(LPD3DXMATERIAL rgmat, DWORD cmat, LPD3DXBUFFER *ppbufMaterials)
  949. {
  950.     HRESULT hr = S_OK;
  951.     DWORD cbTotalStringSize;
  952.     DWORD iCurOffset;
  953.     DWORD imat;
  954.     LPD3DXBUFFER pbufMaterialsOut = NULL;
  955.     LPD3DXMATERIAL rgmatOut;
  956.     DWORD cbName;
  957.  
  958.     // first calculate the amount of memory needed for the string buffers
  959.     cbTotalStringSize = 0;
  960.     for (imat = 0; imat < cmat; imat++)
  961.     {
  962.         if (rgmat[imat].pTextureFilename != NULL)
  963.         {
  964.             cbTotalStringSize += strlen(rgmat[imat].pTextureFilename) + 1;
  965.         }
  966.     }
  967.  
  968.     hr = D3DXCreateBuffer(sizeof(D3DXMATERIAL) * cmat + cbTotalStringSize, &pbufMaterialsOut);
  969.     if (FAILED(hr))
  970.         goto e_Exit;
  971.  
  972.     rgmatOut = (LPD3DXMATERIAL)pbufMaterialsOut->GetBufferPointer();
  973.  
  974.     // fist copy the materials info into the new array (note: string pointers are now incorrect)
  975.     memcpy(rgmatOut, rgmat, sizeof(D3DXMATERIAL) * cmat);
  976.  
  977.     // start allocating strings just after the last material
  978.     iCurOffset = sizeof(D3DXMATERIAL) * cmat;
  979.     for (imat = 0; imat < cmat; imat++)
  980.     {
  981.         if (rgmat[imat].pTextureFilename != NULL)
  982.         {
  983.             rgmatOut[imat].pTextureFilename = ((char*)rgmatOut) + iCurOffset;
  984.  
  985.             cbName = strlen(rgmat[imat].pTextureFilename) + 1;
  986.             memcpy(rgmatOut[imat].pTextureFilename, rgmat[imat].pTextureFilename, cbName);
  987.  
  988.             iCurOffset += cbName;
  989.         }
  990.     }
  991.  
  992.     GXASSERT(iCurOffset == sizeof(D3DXMATERIAL) * cmat + cbTotalStringSize);
  993.  
  994.     *ppbufMaterials = pbufMaterialsOut;
  995.     pbufMaterialsOut = NULL;
  996.  
  997. e_Exit:
  998.     GXRELEASE(pbufMaterialsOut);
  999.     return hr;
  1000. }
  1001.  
  1002. HRESULT
  1003. MergeMaterialBuffers(LPD3DXBUFFER pbufMat1, DWORD cmat1, LPD3DXBUFFER pbufMat2, DWORD cmat2, LPD3DXBUFFER *ppbufMaterials)
  1004. {
  1005.     HRESULT hr = S_OK;
  1006.     D3DXMATERIAL *rgmatTemp = NULL;
  1007.     D3DXMATERIAL *rgmat1;
  1008.     D3DXMATERIAL *rgmat2;
  1009.  
  1010.     if (pbufMat1 == NULL)
  1011.     {
  1012.         if (pbufMat2 == NULL)
  1013.         {
  1014.             *ppbufMaterials = NULL;
  1015.         }
  1016.         else
  1017.         {
  1018.             *ppbufMaterials = pbufMat2;
  1019.             pbufMat2->AddRef();
  1020.         }
  1021.     }
  1022.     else if (pbufMat2 == NULL)
  1023.     {
  1024.         *ppbufMaterials = pbufMat1;
  1025.         pbufMat1->AddRef();
  1026.     }
  1027.     else  // both have materials
  1028.     {
  1029.         rgmat1 = (LPD3DXMATERIAL)pbufMat1->GetBufferPointer();
  1030.         rgmat2 = (LPD3DXMATERIAL)pbufMat2->GetBufferPointer();
  1031.  
  1032.         // make an array contains the color info and pointers to the original strings
  1033.         //   that is the two arrays combined
  1034.         rgmatTemp = new D3DXMATERIAL[cmat1 + cmat2];
  1035.         if (rgmatTemp == NULL)
  1036.         {
  1037.             hr = E_OUTOFMEMORY;
  1038.             goto e_Exit;
  1039.         }
  1040.  
  1041.         memcpy(rgmatTemp, rgmat1, sizeof(D3DXMATERIAL) * cmat1);
  1042.         memcpy(rgmatTemp + cmat1, rgmat2, sizeof(D3DXMATERIAL) * cmat2);
  1043.  
  1044.         // then use the CreateMaterialBuffer call to take and make a buffer out of the "merged" array
  1045.         hr = CreateMaterialBuffer(rgmatTemp, cmat1 + cmat2, ppbufMaterials);
  1046.         if (FAILED(hr))
  1047.             goto e_Exit;
  1048.     }
  1049.  
  1050. e_Exit:
  1051.     delete []rgmatTemp;
  1052.     return hr;
  1053.  
  1054. }
  1055.  
  1056. }
  1057.